package org.apache.zookeeper.server.paxos2;

import org.apache.jute.InputArchive;
import org.apache.jute.OutputArchive;
import org.apache.log4j.Logger;

import java.io.*;
import java.util.BitSet;
import java.util.List;
import java.nio.ByteBuffer;

public class FullExtraShard {

    private RandomAccessFile f;
    private static final Logger LOG = Logger.getLogger(Shard.class);


    public FullExtraShard() {
        try {
            f = new RandomAccessFile(Configuration.storagePath + File.separator + "extra", "rw");
            long length = Configuration.totalSize * (Configuration.noOfStripes - Configuration.writeQuorumSize)/Configuration.noOfStripes;
            if (f.length() != length && length!=0) {
                LOG.info("file size does not match. create an empty file with size=" + length);
                f.setLength(length);
                byte[] tmp = new byte[Configuration.blockSize];
                for (int i = 0; i < (length / Configuration.blockSize); i++)
                    f.write(tmp);
                f.getFD().sync();
            }
        }
        catch (Exception e) {
            LOG.error("Couldn't create storage file", e);
            System.exit(1);
        }
    }

    public void write(long blockId, byte[] data, boolean overwrite) {
        long offset = Mapping.keyToOffsetInShard(blockId);
        long blockIdInShard = blockId / Configuration.noOfStripes;
	    if(blockIdInShard>Configuration.totalSize / Configuration.noOfStripes/Configuration.blockSize)
	        throw new RuntimeException("Cannot write to "+blockIdInShard+" max is "+Configuration.totalSize / Configuration.noOfStripes/Configuration.blockSize);
        try {
            f.seek(offset);
            f.write(data);
        }
        catch (Exception e) {
            LOG.error("Couldn't write blockId=" + blockId, e);
            System.exit(1);
        }
    }

    public void read(long blockId, byte[] data) {
       long offset = Mapping.keyToOffsetInShard(blockId);
        try {
            f.seek(offset);
            f.readFully(data);
        }
        catch (Exception e) {
            LOG.error("Couldn't read blockId=" + blockId, e);
            System.exit(1);
        }
    }


    public void remove(long blockId) {

    }

    public void flush() {
        try {
            f.getFD().sync();
        }
        catch (Exception e) {
            LOG.error("Couldn't flush", e);
            System.exit(1);
        }
    }


    public void serialize(OutputArchive oa, String tag) throws IOException {

        flush();
    }

    public void deserialize(InputArchive ia, String tag) throws IOException {

    }

    public void close() {
        try {
            f.close();
        }
        catch (Exception e) {
            LOG.error("Couldn't close", e);
        }
    }
}